﻿
namespace TFSChangeLogCL.GeneralUtilities
{
    using System;
    using System.IO;
    using System.Xml;
    using System.Xml.Schema;

    // call Validate to validate an xml file/stream against an xsd file/stream
    // returns true if valid, false otherwise. GetError will return
    // any error messages taht were produced in the last validation

    /// <summary>Summary description for <see cref="XML_XSD_Validator"/> class.</summary>
    public static class XML_XSD_Validator
    {
        /// <summary>Summary description for class level field of type <c>int</c>.</summary>
        private static int numErrors = 0;

        /// <summary>Summary description for class level field of type <c>string</c>.</summary>
        private static string msgError = string.Empty;

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        /// <param name="xml">TODO: Summary description for <c>xml</c> parameter of type <c>System.IO.Stream</c>.</param>
        /// <param name="xsdFilename">TODO: Summary description for <c>xsdFilename</c> parameter of type <c>string</c>.</param>
        /// <returns>TODO: returns an object of type <c>bool</c>.</returns>
        public static bool Validate(Stream xml, string xsdFilename)
        {
            return Validate(xml, GetFileStream(xsdFilename));
        }

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        /// <param name="xmlFilename">TODO: Summary description for <c>xmlFilename</c> parameter of type <c>string</c>.</param>
        /// <param name="xsd">TODO: Summary description for <c>xsd</c> parameter of type <c>System.IO.Stream</c>.</param>
        /// <returns>TODO: returns an object of type <c>bool</c>.</returns>
        public static bool Validate(string xmlFilename, Stream xsd)
        {
            var xmlFilestream = GetFileStream(xmlFilename);
            if (xmlFilestream != null)
            {
            }
            else
            {
                msgError = "\"" + xmlFilename + "\" file not found.";
                throw new XmlException(msgError);
            }

            return Validate(xmlFilestream, xsd);
        }

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        /// <param name="xmlFilename">TODO: Summary description for <c>xmlFilename</c> parameter of type <c>string</c>.</param>
        /// <param name="xsdFilename">TODO: Summary description for <c>xsdFilename</c> parameter of type <c>string</c>.</param>
        /// <returns>TODO: returns an object of type <c>bool</c>.</returns>
        public static bool Validate(string xmlFilename, string xsdFilename)
        {
            return Validate(GetFileStream(xmlFilename), GetFileStream(xsdFilename));
        }

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        /// <param name="xml">TODO: Summary description for <c>xml</c> parameter of type <c>System.IO.Stream</c>.</param>
        /// <param name="xsd">TODO: Summary description for <c>xsd</c> parameter of type <c>System.IO.Stream</c>.</param>
        /// <returns>TODO: returns an object of type <c>bool</c>.</returns>
        public static bool Validate(Stream xml, Stream xsd)
        {
            ClearErrorMessage();
            try
            {
                XmlTextReader tr = new XmlTextReader(xsd);
                XmlSchemaSet schema = new XmlSchemaSet();
                schema.Add(null, tr);

                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ValidationType = ValidationType.Schema;
                settings.Schemas.Add(schema);
                settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
                settings.ValidationEventHandler += new ValidationEventHandler(ErrorHandler);
                XmlReader reader = XmlReader.Create(xml, settings);

                // Validate XML data
                while (reader.Read())
                    {
                    }

                reader.Close();

                if (xml != null)
                    {
                    xml.Dispose();
                    }

                // exception if validation failed
                if (numErrors > 0)
                    {
                    throw new Exception(msgError);
                    }

                return true;
            }
            catch
            {
                if (xml != null)
                {
                    xml.Dispose();
                }

                msgError = "XML validation failed. \n" + msgError;
                throw new XmlException(msgError);
            }
        }

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        /// <param name="sender">TODO: Summary description for <c>sender</c> parameter of type <c>object</c>.</param>
        /// <param name="args">TODO: Summary description for <c>args</c> parameter of type <c>System.Xml.Schema.ValidationEventArgs</c>.</param>
        private static void ErrorHandler(object sender, ValidationEventArgs args)
        {
            msgError = msgError + "\n" + args.Message;
            numErrors++;
        }

        // if a validation error occurred, this will return the message

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        /// <returns>TODO: returns an object of type <c>string</c>.</returns>
        public static string GetError()
        {
            return msgError;
        }

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        private static void ClearErrorMessage()
        {
            msgError = string.Empty;
            numErrors = 0;
        }

        // returns a stream of the contents of the given filename

        /// <summary>Summary description for <c>XML_XSD_Validator</c> method.</summary>
        /// <param name="filename">TODO: Summary description for <c>filename</c> parameter of type <c>string</c>.</param>
        /// <returns>TODO: returns an object of type <c>System.IO.Stream</c>.</returns>
        private static Stream GetFileStream(string filename)
        {
            try
            {
                return new FileStream(filename, FileMode.Open);
            }
            catch
            {
                return null;
            }
        }
    }
}
